import ctypes
import datetime
import os
import queue
import socket
import sys
import threading

import gevent
import win32api
import win32con

import settings
from db_tools.db_handler import DbHandler
from eap_socket.client_tool import *
from eap_socket.xml_parser_helper import *
from tools.send_to_ui_tools import *

remote_command_map = {
    "1": "Start 通知机台开始投板",
    "2": "Stop 通知机台停止板",
    "3": "Inspect Start 通知机台开始做首件",
    "4": "Resume 通知机台复机",
    "5": "Open Buffer 通知机台启动暂存",
    "6": "Close Buffer 通知机台关闭暂存",
    "7": "Unload Carrier 通知机台下料",
    "8": "Panel OK 通知 Panel 正常",
    "9": "Panel NG 通知 Panel 异常",
    "10": "陪镀板读板完成 放陪镀板工位",
    "11": "Inspect OK 首件 OK",
    "12": "Inspect NG 首件 NG",
    "13": "切换下料工位",
    "14": "投板机放板延时",
    "15": "通知压机开始压板"
}

db = DbHandler()


class HdClient(object):
    __instance__ = None
    __initFlag__ = False
    __lock__ = threading.Lock()

    sock = None
    eapOnline = False
    eapMsgSendQueue = queue.Queue()
    loopDelay = 2
    msgShowList = []

    remode_command = "Eap下发的远程命令"

    def __new__(cls, *args, **kwargs):
        if cls.__instance__ is None:
            with cls.__lock__:
                if cls.__instance__ is None:
                    cls.__instance__ = super(HdClient, cls).__new__(cls)
        return cls.__instance__

    def __init__(self):

        self.eqName = None
        self.eapIp = None
        self.port = None
        self.operationMode = None
        self.askDuration = None
        self.currentTimeDuration = None
        self.totalCountDuration = None
        self.cimMessageDuration = None
        self.msgShowMaxLength = None
        if not self.__initFlag__:
            self.__initFlag__ = True
            eap_print("HdClient 进行初始化,获取相关的参数,当前时间: {}".format(get_now_time_str()))
            self.get_eap_params()
        self.askRequestThread = threading.Thread(target=self.ask_eap_there_request, name="ask_request_thread")
        self.sendMsgThread = threading.Thread(target=self.send_message_to_eap, name="send_msg_thread")
        self.recvMsgThread = threading.Thread(target=self.receive_message_from_eap, name="recv_msg_thread")
        self.managerThread = threading.Thread(target=self.thread_manager, name="thread_manager")

        self.orderId = "001"
        self.orderHeight = 200
        self.orderWidth = 299
        self.orderCropperThickness = "0 ~ 0.33"
        self.orderEdge = 15
        self.EapChangeOrderFlag = False
        self.orderTotalCount = 0
        self.processCount = 0
        self.processCountNg = 0
        self.processCountOk = 0
        self.jobId = "123"
        self.processCode = "1"  # 1. 建立生产任务 2. 更新生产任务(仅变更数量) 3. 删除生产任务 4. 开始生产任务 5. 结束生产任务
        self.cutArea = "1000"

        self.eap_status = "3"  # 1.Run 运行 2. Pause 暂停 3: Idle 待机 4: Down 故障 5:PM保养 6:Ready 准备
        self.green_towner = "3"  # 1: 亮 2. 闪 3. 灭
        self.yellow_towner = "1"  #
        self.red_towner = "3"

        self.indentify_type = "1"  # 1: 人员上岗  2:人员下岗 3: 人员上岗验证
        self.operator_id = "Fioman"  # 人员ID
        self.login_type = "1"  # 1: 登录系统 2: 观看机密界面 3: 修改相关设定
        self.autoSendCloseCimStart = 0

        self.currentUser = "当前无用户使用"
        self.requestOrderId = "请求的工单号"

    def update_user_id(self, userId):
        if userId == "":
            return "Error", "输入的用户名为空"
        self.currentUser = userId
        self.operator_id = self.currentUser
        return "ok", self.currentUser

    def user_login(self):
        """
        上岗
        :return:
        """
        self.indentify_type = "1"  # 人员上岗
        self.put_msg_to_queue("OperatorLoginLogoutReport")
        return "ok"

    def user_logout(self):
        """
        下岗
        :return:
        """
        self.indentify_type = "2"  # 人员下岗
        self.put_msg_to_queue("OperatorLoginLogoutReport")
        return "ok"

    def receive_message_from_eap(self):
        while settings.IS_MAIN_ALIVE:
            if self.eapOnline and self.operationMode != "0":
                try:
                    recvData = self.sock.recv(BUFFER_SIZE)
                    # 将recvData的粘包问题解决掉,二进制的字符串
                    recvDataList = split_recv_data(recvData)
                    for recvData in recvDataList:
                        if recvData:
                            msgName, bodyDict, retCode, transactionId = parse_recv_msg(recvData)
                            msgInfo = "从EAP接收到消息：msgName = {},bodyDict = {},retCode = {}".format(
                                msgName, bodyDict, retCode)
                            eap_print(msgInfo)
                            self.add_message_to_msgshow("recv", [msgName, bodyDict, retCode])
                            self.deal_recv_message(msgName, bodyDict, retCode, transactionId)
                            gevent.sleep(self.loopDelay)
                except Exception as e:
                    eap_print("in receive_message_from_eap() error: {}".format(str(e)))
            else:
                gevent.sleep(self.loopDelay)

    def send_message_to_eap(self):
        """
        发送消息到EAP,根据eapMsgSendQueue
        eapMsgSendQueue有两种消息,一个是主动消息,一个是回复消息.
        回复消息的话里面放的是列表,包括
        :return:
        """
        while settings.IS_MAIN_ALIVE:
            if self.eapOnline and self.operationMode != "0":
                try:
                    # 关闭远程讯息
                    if self.autoSendCloseCimStart != 0:
                        if time.time() - self.autoSendCloseCimStart > self.cim_interval_time:
                            send_cim_msg_to_ui("")
                            self.autoSendCloseCimStart = 0
                    if not self.eapMsgSendQueue.empty():
                        msgSendType = self.eapMsgSendQueue.get()
                        if isinstance(msgSendType, list):
                            msgName = msgSendType[0]
                            transactionId = msgSendType[1]
                            eap_print("回复EAP消息: {}".format(msgName))
                        else:
                            msgName = msgSendType
                            transactionId = None
                            eap_print("主动发送消息到EAP: {}".format(msgName))
                        data = self.get_send_data_by_type(msgName, transactionId)
                        if data is None:
                            eap_print("in send_message_to_eap()  data 获取为None,要发送的数据获取失败")
                            continue
                        res = self.send_data_to_eap(data)
                        if res:
                            eap_print("消息: {} 发送成功!".format(msgName))
                        else:
                            eap_print("消息: {} 发送失败!".format(msgName))
                    gevent.sleep(self.loopDelay)
                except Exception as e:
                    eap_print("in send_message_to_eap() " + str(e))
                    gevent.sleep(self.loopDelay)
            else:
                gevent.sleep(self.loopDelay)

    def send_data_to_eap_old(self, data):
        try:
            msgSend = bytes(chr(2), encoding="ascii") + data + bytes(chr(3), encoding="ascii")
            if self.sock is None:
                return False
            self.sock.sendall(msgSend)
            return True
        except Exception as e:
            eap_print("in send_data_to_eap() Error: {}".format(str(e)))
            return False

    def send_data_to_eap(self, data):
        try:
            data = data.encode("utf-16le")
            msgSend = bytes(chr(2), encoding="ascii") + data + bytes(chr(3), encoding="ascii")
            if self.sock is None:
                return False
            self.sock.sendall(msgSend)
            return True
        except Exception as e:
            eap_print("in send_data_to_eap() Error: {}".format(str(e)))
            return False

    def send_data_to_eap_old_2(self, data):
        try:
            HEAD_CODE = 0x02
            TAIL_CODE = 0x03
            dataArray = bytearray()
            dataArray.append(HEAD_CODE)
            dataUtf16 = data.encode("utf-16")
            dataArray.extend(dataUtf16)
            dataArray.append(TAIL_CODE)
            if self.sock is None:
                return False
            self.sock.sendall(dataArray)
            return True
        except Exception as e:
            eap_print("in send_data_to_eap() Error: {}".format(str(e)))
            return False

    def thread_manager(self):
        """
        线程管理类,用来管理其他的线程
        :return:
        """
        while settings.IS_MAIN_ALIVE:
            try:
                if not self.askRequestThread.is_alive():
                    self.askRequestThread = threading.Thread(target=self.ask_eap_there_request,
                                                             name="ask_request_thread")
                    self.askRequestThread.setDaemon(True)
                    self.askRequestThread.start()
                if not self.sendMsgThread.is_alive():
                    self.sendMsgThread = threading.Thread(target=self.send_message_to_eap,
                                                          name="send_msg_thread")
                    self.sendMsgThread.setDaemon(True)
                    self.sendMsgThread.start()
                if not self.recvMsgThread.is_alive():
                    self.recvMsgThread = threading.Thread(target=self.receive_message_from_eap,
                                                          name="recv_msg_thread")
                    self.recvMsgThread.setDaemon(True)
                    self.recvMsgThread.start()

                gevent.sleep(5)
            except Exception as e:
                eap_print("in thread_manager()" + str(e))

    def ask_eap_there_request(self):
        while settings.IS_MAIN_ALIVE:
            if self.eapOnline:
                self.put_msg_to_queue("AreYouThereRequest")
                gevent.sleep(self.askDuration)
            else:
                gevent.sleep(self.loopDelay)

    def get_eap_params(self):
        try:
            res, data = db.get_eap_params()
            if res != "ok":
                eap_print("in get_eap_params() " + data)
                return []
            else:
                self.eqName = data.get("eqName", "HD001")
                self.eapIp = data.get("eapIp", "127.0.0.1")
                self.port = int(data.get("port", 5000))
                # {"1": 手动模式, "2": 自动模式, "3": 首件模式}
                self.controlMode = data.get("controlMode", "离线模式")
                self.operationMode = data.get("operationMode", "自动模式")
                self.askDuration = int(data.get("askDuration", "60"))
                self.currentTimeDuration = int(data.get("currentTimeDuration", "60"))
                self.totalCountDuration = int(data.get("totalCountDuration", "10"))
                self.cimMessageDuration = int(data.get("cimMessgaeDuration", "60"))
                self.msgShowMaxLength = int(data.get("msgShowLength", 15))
                return [data]
        except Exception as e:
            eap_print("in get_eap_params() " + str(e))

    def get_datetime_sync_command_reply_data(self, msgName, transactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "return_code": "1"  # 0是NG,1是OK
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_date_time_sysnc_replay_data(msgName, bodyDict, retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_equipment_job_data_process_report(self, msgName, transactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "job_id": self.jobId,
            "total_panel_count": self.orderTotalCount,
            "OK_process_panel_count": self.processCountOk,
            "NG_process_panel_count": self.processCountNg,
            "process_code": self.processCode,
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_equipment_job_data_process_report_data(msgName, bodyDict, retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_control_mode_command_reply_data(self, msgName, transactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "return_code": "1"  # 0是NG,1是OK
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_control_mode_command_reply_data(msgName, bodyDict, retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_process_data_report_data(self, msgName, transactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "sub_eqp_id": "",
            "job_id": self.jobId,
        }

        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_process_data(msgName, bodyDict, [("P01", self.orderId),
                                              ("P02", self.processCount),
                                              ("P03", self.cutArea)], retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_eqp_alarm_report_data(self, msgName, alarmInfo):
        bodyDict = {
            "eqp_id": self.eqName,
            "report_type": alarmInfo[0],
            "alarm_type": alarmInfo[1]
        }

        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_alarm_report_data(msgName, bodyDict, alarmInfo[2], retDict, None)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_operator_login_logout_report_data(self, msgName, transactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "identify_type": self.indentify_type,
            "operator_id": self.operator_id,
            "login_type": self.login_type,
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_eqp_current_status_data(msgName, bodyDict, retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_eqp_recipe_setup_report(self, msgName, transactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "process_id": self.jobId,
            "recipe_path": "",
            "cam_path": "",
            "setup_result": "1"  # 0:NG, 1:OK
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_eqp_current_status_data(msgName, bodyDict, retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_eqp_current_status_data(self, msgName, transactionId):

        bodyDict = {
            "eqp_id": self.eqName,
            "sub_eqp_id": "",
            "eqp_status": self.eap_status,
            "green_towner": self.green_towner,
            "yellow_towner": self.yellow_towner,
            "red_towner": self.red_towner
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_eqp_current_status_data(msgName, bodyDict, retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_eqp_operation_mode_data(self, msgName, trasactionId):
        if self.operationMode == "手动模式":
            operationMode = "1"
        elif self.operationMode == "自动模式":
            operationMode = "2"
        else:
            operationMode = "3"

        bodyDict = {
            "eqp_id": self.eqName,
            "operation_mode": operationMode
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_eqp_control_mode_data(msgName, bodyDict, retDict, trasactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_eqp_control_mode_data(self, msgName, trasactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "control_mode": "1" if self.controlMode == "离线本地模式" else "2"  # 0是NG,1是OK
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_eqp_control_mode_data(msgName, bodyDict, retDict, trasactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_recipe_parameter_request_reply(self, msgName, trasactionId):
        orderData = db.get_order_by_order_id(self.requestOrderId)

        bodyDict = {
            "eqp_id": self.eqName,
            "recipe_id": self.requestOrderId  # 0是NG,1是OK
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_recipe_parameter_reqeust_reply_data(msgName, bodyDict, orderData, retDict, trasactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_job_data_download_reply_data(self, msgName, trasactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "return_code": "1"  # 0是NG,1是OK
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_job_data_download_reply_data(msgName, bodyDict, retDict, trasactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_remote_control_command_reply_data(self, msgName, transactionId):
        bodyDict = {
            "eqp_id": self.eqName,
            "return_code": "1"  # 0是NG,1是OK
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", msgInfo=[msgName, bodyDict, retDict])
        pack_remote_control_command_reply_data(msgName, bodyDict, retDict, transactionId)
        with open(settings.MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_are_you_there_request_data(self, msgName):
        """
        获取AreYouThereRequest 消息的数据
        :param msgName:
        :return:
        """
        bodyDict = {
            "eqp_id": self.eqName,
            "server_ip": self.eapIp
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        # 1. 先添加到要发送和接收的消息列表中,可以让界面上显示
        self.add_message_to_msgshow("send", [msgName, bodyDict, retDict])
        # 2. 将要发送给EAP的消息封装成XML文件格式,并写入到对应的文件中
        pack_are_you_there_request_msg_xml(msgName, bodyDict, retDict)
        # 3. 读取对应的文件内容
        with open(settings.ASK_MSG_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_trace_data_reply_data(self, msgName, transactionId):
        data = db.get_trace_data_reply()[1]
        bodyDict = {
            "eqp_id": self.eqName,
            "sub_eqp_id": ""
        }
        trace_data_list = [
            ("D01", data.get("D01")),
            ("D02", data.get("D02")),
            ("D03", data.get("D03")),
            ("D04", data.get("D04")),
            ("D05", data.get("D05")),
            ("D06", data.get("D06")),
            ("D07", data.get("D07")),
            ("D08", data.get("D08")),
            ("D09", data.get("D09")),
            ("D10", data.get("D10")),
            ("D11", data.get("D11")),
            ("D12", data.get("D12")),
            ("D13", data.get("D13")),
            ("D14", data.get("D14")),
            ("D15", data.get("D15")),
        ]
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", [msgName, bodyDict, retDict])
        pack_trace_data_replay_msg_xml(msgName, bodyDict, trace_data_list, retDict, transactionId)
        with open(MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def get_initial_data_reply_data(self, msgName, transactionId):
        data = db.get_init_data_reply()[1]
        bodyDict = {
            "eqp_id": data.get("eqp_id", "default"),
            "control_mode": data.get("control_mode", "default"),
            "operation_mode": data.get("operation_mode", "default"),
            "eqp_status": data.get("eqp_status", "default"),
            "recipe_name": data.get("recipe_name", "default"),
            "recipe_path": data.get("recipe_path", "default"),
            "cam_path": data.get("cam_path", "default"),
            "job_id": data.get("job_id", "default"),
            "total_panel_count": data.get("total_panel_count", "default"),
            "process_panel_count": data.get("process_panel_count", "default"),
        }
        retDict = {
            "returncode": "0",
            "returnmessage": ""
        }
        self.add_message_to_msgshow("send", [msgName, bodyDict, retDict])
        pack_init_data_replay_msg_xml(msgName, bodyDict, retDict, transactionId)
        with open(MSG_SEND_PATH, "r", encoding="utf-8") as f:
            data = f.read()
        return data

    def system_is_admin(self):
        """
        判断当前系统是否具有管理员权限
        :return: 如果具有管理员权限，返回True，如果没有管理员权限，返回False
        """
        try:
            return ctypes.windll.shell32.IsUserAnAdmin()
        except Exception as e:
            print("in system_is_admin() error : {}".format(str(e)))
            return False

    def get_send_data_by_type(self, msgName, transactionId):
        data = None
        try:
            if msgName == "AreYouThereRequest":
                data = self.get_are_you_there_request_data(msgName)
            elif msgName == "InitialDataReply":
                data = self.get_initial_data_reply_data(msgName, transactionId)
            elif msgName == "EquipmentJobDataProcessReport":
                data = self.get_equipment_job_data_process_report(msgName, transactionId)
            elif msgName == "ControlModeCommandReply":
                data = self.get_control_mode_command_reply_data(msgName, transactionId)
            elif msgName == "DateTimeSyncReply":
                data = self.get_datetime_sync_command_reply_data(msgName, transactionId)
            elif msgName == "InitialDataReply":
                data = self.get_initial_data_reply_data(msgName, transactionId)
            elif msgName == "TraceDataRequestReply":
                data = self.get_trace_data_reply_data(msgName, transactionId)
            elif msgName == "RemoteControlCommandReply":
                data = self.get_remote_control_command_reply_data(msgName, transactionId)
            elif msgName == "JobDataDownloadReply":
                data = self.get_job_data_download_reply_data(msgName, transactionId)
            elif msgName == "RecipeParameterRequestReply":
                data = self.get_recipe_parameter_request_reply(msgName, transactionId)
            elif msgName == "EquipmentControlMode":
                data = self.get_eqp_control_mode_data(msgName, transactionId)
            elif msgName == "EquipmentOperationMode":
                data = self.get_eqp_operation_mode_data(msgName, transactionId)
            elif msgName == "EquipmentCurrentStatus":
                data = self.get_eqp_current_status_data(msgName, transactionId)
            elif msgName == "EquipmentAlarmReport":
                data = self.get_eqp_alarm_report_data(msgName, transactionId)
            elif msgName == "EquipmentRecipeSetupReport":
                data = self.get_eqp_recipe_setup_report(msgName, transactionId)
            elif msgName == "OperatorLoginLogoutReport":
                data = self.get_operator_login_logout_report_data(msgName, transactionId)
            elif msgName == "ProcessDataReport":
                data = self.get_process_data_report_data(msgName, transactionId)
            else:
                eap_print("消息类型 {} 无法识别,没有做对应的消息处理,要发送的数据获取失败!".format(msgName))
        except Exception as e:
            eap_print("in get_send_data_by_type() " + str(e))
            return data
        return data

    def add_message_to_msgshow(self, msgType, msgInfo):
        """
        将消息不管是接收到的还是发送的都放到消息列表中去,然后在前端显示
        :param msgType:消息类型一般是send或者是recv
        :param msgInfo:具体要显示的消息,包括消息头名称header,消息主题body,消息结果码
        :return:
        """
        msgSend = []
        if msgType == "recv":
            msgHead = " 从EAP接收消息"
        else:
            msgHead = " 发送消息到EAP"

        msgHead = get_now_time_str() + msgHead
        msgSend.append(msgHead)
        msgBody = ["消息类型:{}".format(msgInfo[0]), "消息主体:{}".format(msgInfo[1]),
                   "消息结果码: {}".format(msgInfo[2])]
        msgSend.append(msgBody)
        # 只显示前面几条内容,如果大于所要显示的最大个数,弹出索引为0的元素,它最先被放入
        if len(self.msgShowList) >= self.msgShowMaxLength:
            self.msgShowList.pop(0)

        self.msgShowList.append(msgSend)
        print("当前界面上显示的消息为:{}".format(self.msgShowList))
        msgSend2UI = self.msgShowList[::-1]  # 这里显示的时候倒序显示,保证最近的一条消息最先显示到最上面
        msgVal = {
            "val": "updateEapMsg",
            "info": msgSend2UI
        }
        send_eap_msg_state_to_ui(msgVal)

    def connect_eap(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.modify_buffer_size(self.sock)
        # self.sock.settimeout(2)  # 设置超时连接时间为2秒,不能设置超时时间设置超时时间之后接收消息案例也会一直有超时时间
        try:
            self.sock.connect((self.eapIp, self.port))
            self.eapOnline = True
            eap_print("连接EAP成功!")
            return "ok"
        except Exception as e:
            eap_print("连接EAP失败,失败原因: {}".format(str(e)))
            self.sock.close()
            self.sock = None
            self.eapOnline = False
            return "连接超时,请检查网线是否插好以及EAP的IP地址和端口号是否正确"

    @staticmethod
    def modify_buffer_size(hdSock):
        # 获取当前套接字关联的选项,socket.SOL_SOCKET,正在使用的socket,socket.SOCK_STREAM发送缓存区的大小
        hdSock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
        hdSock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)

        # 设置TCP套接字关联的选项
        # socket.TCP_NODELAY TCP层套接口选项
        # socket.TCP_NODELAY.表示禁用了Nagle,允许小包发送.不用等很多的包折合一起再发送的问题.适用于数据量小的项目.
        hdSock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)

        # 设置发送缓存区套接字关联的选项
        hdSock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, BUFFER_SIZE)
        # 设置接收缓存区套接字关联的选项
        hdSock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, BUFFER_SIZE)

    def save_eap_params(self, eapParams):
        try:
            if eapParams.get("controlMode") != self.controlMode:
                # 模式发生改变,上报
                self.eapMsgSendQueue.put("EquipmentControlMode")
            if eapParams.get("operationMode") != self.operationMode:
                self.eapMsgSendQueue.put("EquipmentOperationMode")
            return db.save_eap_params(eapParams)
        except Exception as e:
            eap_print("in save_eap_params(): error: {}".format(str(e)))
            return str(e)

    def disconnect_eap(self):
        """
        断开EAP连接
        :return:
        """
        if self.sock is not None:
            self.sock.close()
            self.sock = None
            self.eapOnline = False
        return "ok"

    def run_as_admin(self):
        if sys.version_info[0] == 3 and os.name == 'nt':
            script = os.path.abspath(sys.argv[0])
            params = ' '.join([script] + sys.argv[1:])
            try:
                ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, params, None, 1)
            except Exception as e:
                print(e)
            sys.exit(0)

    def calibration_datetime(self, serviceTime):
        try:
            year = int(serviceTime[:4])
            month = int(serviceTime[4:6])
            day = int(serviceTime[6:8])
            hour = int(serviceTime[8:10])
            min = int(serviceTime[10:12])
            sec = int(serviceTime[12:])
            print("year = {},month = {},day = {},hour = {},min = {},sec = {}".format(year, month, day, hour, min, sec))
            # 先判断是否具有管理员权限:
            isAdmin = self.system_is_admin()
            if not isAdmin:
                # self.run_as_admin()
                win32api.MessageBox(0, "请设置管理员权限，否则修改时间不成功，没有权限", '错误', win32con.MB_ICONWARNING)
                ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
            date = datetime.datetime(year, month, day, hour, min, sec, 0)
            wDay = int(date.weekday())
            win32api.SetSystemTime(year, month, wDay, day, hour - 8, min, sec, 0)
            return True
        except Exception as e:
            print("in calibration_datetime() error : {}".format(str(e)))
            return False

    def deal_recv_message(self, msgType, bodyDict, retCode, transactionId):
        """
        处理接收到的各种消息，这个函数很重要.
        :param msgType: 消息的类型
        :param bodyDict: 消息的主体内容
        :param transactionId:接收到的消息的transactionId
        :return:
        """
        msgReply = None
        if msgType == "InitialDataRequest":
            # 当接收到这个消息的时候，需要回复。将要回复的消息类型加入到队列
            msgReply = "InitialDataReply"

        elif msgType == "TraceDataRequest":
            msgReply = "TraceDataRequestReply"
        elif msgType == "DateTimeSyncCommand":
            # 时间校准命令
            serviceTime = bodyDict["date_time"]
            self.calibration_datetime(serviceTime)
            msgReply = "DateTimeSyncReply"
        elif msgType == "ControlModeCommand":
            # 模式更改
            controlMode = bodyDict.get("control_mode")  # 操作模式1, 离线本地模式 2, 远程在线模式
            msgReply = "ControlModeCommandReply"
            self.controlMode = "离线本地模式" if controlMode == "1" else "在线远程模式"
            newData = {
                "controlMode": controlMode
            }
            db.save_eap_params(newData)
            newParams = db.get_eap_params()[1]
            send_eap_params_update_state_to_ui(newParams)
        elif msgType == "RemoteControlCommand":  # 远程命令
            self.remote_command = bodyDict.get("remote_command")
            eap_print("接收到远程命令: {}".format(self.remote_command))
            msgReply = "RemoteControlCommandReply"
        elif msgType == "JobDataDownload":  # 任务下发命令
            msgReply = "JobDataDownloadReply"
            # 解析的任务下发的宽和高以及铜箔厚度
            self.parse_recipe_info(bodyDict)
            self.EapChangeOrderFlag = True
            eap_print("接收到任务下发命令:{}".format(bodyDict))
        elif msgType == "CIMMessageCommand":
            # EAP发送讯息给设备，需要弹框显示这条消息
            self.cim_interval_time = int(bodyDict.get("interval_second_time"))
            self.cim_message_code = bodyDict.get("message_code")
            self.cim_message = bodyDict.get("cim_message")
            if self.cim_interval_time != 0:
                self.autoSendCloseCimStart = time.time()
            else:
                self.autoSendCloseCimStart = 0
            cimMessage = "远程讯息内容: {}, 对应的cim_message_code: {}".format(self.cim_message, self.cim_message_code)
            send_cim_msg_to_ui(cimMessage)

        elif msgType == "RecipeParameterRequest":
            self.requestOrderId = bodyDict.get("recipe_id")
            eap_print("接收到工单参数请求,请求的工单参数: {}".format(bodyDict))
            msgReply = "RecipeParameterRequestReply"

        elif msgType == "Recipe Body Request":
            self.requestRecipeName = bodyDict["recipe_name"]
            msgReply = "RecipeParameterRequestReply"

        elif msgType == "Recipe Name Change Request":
            self.changeRecipeName = bodyDict["recipe_name"]
            msgReply = "Recipe Name Change Reply"

        elif msgType == "User Login Logout Reply" and self.userLoginRepalyRecvFlag:
            if retCode == "0":
                query = {}
                newValues = {
                    "$set": {
                        "userLogin": self.loginState,
                    }
                }
                #     self.js.db.update_data(self.js.db.params_db, "deviceInfo", query, newValues)
                #     self.userLoginRepalyRecvFlag = False
                #     if self.loginReportClearFlag:
                #         self.js.set_alarm_info("L", "R", "9")
                #         self.loginReportClearFlag = False
                # else:
                #     self.js.send_2_ui({"val": "updateLoginReport", "info": "员工上下岗失败,请确认工人ID是否正确,更新后重新点击上下岗."})
                #     self.loginReportClearFlag = True
                #     self.userLoginRepalyRecvFlag = False
                self.js.set_alarm_info("L", "S", "9")
        elif msgType == "File Path And Lot Information Download":
            pass
            # print("接受到工单切换的请求,参数: {}".format(bodyDict))
            # eapLogger.debug("从EAP接收到工单切换请求: {}".format(bodyDict))
            # self.js.eap_change_order(bodyDict)
            # msgReply = "File Path And Lot Information Download Reply"
        if msgReply is not None:
            self.eapMsgSendQueue.put([msgReply, transactionId])
            # self.js.eapMsgQueue.put([msgReply,transactionId])

    def parse_recipe_info(self, data):
        self.orderTotalCount = int(data.get("total_panel_count"))
        self.jobId = data.get("job_id")
        self.orderId = data.get("R01")
        self.orderHeight = round(float(data.get("R03")) / 25.4, 2)
        self.orderWidth = round(float(data.get("R02")) / 25.4, 2)
        self.orderCropperThickness = float(data.get("R04"))
        if 0 <= self.orderCropperThickness <= 0.33:
            self.orderCropperThickness = "0 ~ 0.33"
        elif 0.34 <= self.orderCropperThickness <= 1:
            self.orderCropperThickness = "0.34 ~ 1"
        elif 1.1 < self.orderCropperThickness <= 1.5:
            self.orderCropperThickness = "1.1 ~ 1.5"
        elif 1.6 <= self.orderCropperThickness <= 2:
            self.orderCropperThickness = "1.6 ~ 2"
        else:
            self.orderCropperThickness = "2 ~"
        self.orderEdge = int(data.get("R05"))

    def put_msg_to_queue(self, msgPut):
        """
        将消息加入到队列中,如果Eap在线
        :param msgPut:
        :return:
        """
        if self.eapOnline and "在线" in self.controlMode:
            self.eapMsgSendQueue.put(msgPut)
